unit hadevisitormanager;

{$mode objfpc}{$H+}

interface

uses
  Classes,
  SysUtils,
  hademapbase,
  hadebasevisitor,
  hadeconnectionmanager,
  hadecriteria;

type

  { THadeVisitorObject }

  THadeVisitorObject = class
  private
    FVisitorClass: THadeVisitorClass;
  public
    property VisitorClass: THadeVisitorClass read FVisitorClass write FVisitorClass;

    constructor Create(const AVisitorClass: THadeVisitorClass);
  end;

  { THadeVisitorManager }

  THadeVisitorManager = class(THadeMapBase)
  private
    constructor Create;
  protected
    function getItem(index: integer): THadeVisitorObject; reintroduce;
  public
    property Items[index: integer]: THadeVisitorObject read getItem;

    function Find(const s: shortstring): THadeVisitorObject; reintroduce;
    procedure RegisterVisitor(const AName: shortstring;
      const AObject: THadeVisitorClass);

    procedure ExecuteVisitor(const AVisitorName: string;
      const AHadeObject: THadeVisited; const AConnection: THadeConnection;
      ACriteria: THadeCriteria; APropsOrder: array of string;
      AOrderType: THadeOrderType; limit: integer = 0; offset: integer = 0);

    procedure ExecuteVisitor(const AVisitorName: string;
      const AHadeObject: THadeVisited; const AConnection: THadeConnection);
  end;

function GHadeVisitorManager: THadeVisitorManager;

implementation

uses
  hadeexception,
  hadeconst;

var
  FHadeVisitorManager: THadeVisitorManager = nil;

function GHadeVisitorManager: THadeVisitorManager;
begin
  { TODO 2 -oFajar -cOPF : make thread safe }
  if not Assigned(FHadeVisitorManager) then
    FHadeVisitorManager := THadeVisitorManager.Create;
  Result := FHadeVisitorManager;
end;

{ THadeVisitorObject }

constructor THadeVisitorObject.Create(const AVisitorClass: THadeVisitorClass);
begin
  FVisitorClass := AVisitorClass;
end;

{ THadeVisitorManager }

constructor THadeVisitorManager.Create;
begin
  inherited Create(True);
end;

function THadeVisitorManager.getItem(index: integer): THadeVisitorObject;
begin
  Result := THadeVisitorObject(inherited getItem(index));
end;

function THadeVisitorManager.Find(const s: shortstring): THadeVisitorObject;
begin
  Result := THadeVisitorObject(inherited Find(s));
end;

procedure THadeVisitorManager.RegisterVisitor(const AName: shortstring;
  const AObject: THadeVisitorClass);
var
  FVisitorObject: THadeVisitorObject;
begin
  FVisitorObject := THadeVisitorObject.Create(AObject);
  if inherited add(AName, FVisitorObject) = -1 then
    raise EHadeVisitorNameExists.createFmt(CHadeVisitorNameExists, [AName]);
end;

procedure THadeVisitorManager.ExecuteVisitor(const AVisitorName: string;
  const AHadeObject: THadeVisited; const AConnection: THadeConnection;
  ACriteria: THadeCriteria; APropsOrder: array of string;
  AOrderType: THadeOrderType; limit: integer; offset: integer);
var
  FVisitor: THadeVisitor;
  tmp: THadeVisitorObject;
begin
  tmp := Find(AVisitorName);
  if tmp = nil then
    raise EHadeVisitorNoFound.CreateFmt(CHadeVisitorNoFound, [AVisitorName]);
  FVisitor := tmp.VisitorClass.Create(AConnection);
  try
    AHadeObject.Iterate(FVisitor, ACriteria, APropsOrder, AOrderType, limit, offset);
  finally
    FreeAndNil(FVisitor);
  end;
end;

procedure THadeVisitorManager.ExecuteVisitor(const AVisitorName: string;
  const AHadeObject: THadeVisited; const AConnection: THadeConnection);
var
  FVisitor: THadeVisitor;
  tmp: THadeVisitorObject;
begin
  tmp := Find(AVisitorName);
  if tmp = nil then
    raise EHadeVisitorNoFound.CreateFmt(CHadeVisitorNoFound, [AVisitorName]);

  FVisitor := tmp.VisitorClass.Create(AConnection);
  try
    AHadeObject.iterate(FVisitor);
  finally
    FreeAndNil(FVisitor);
  end;
end;

initialization
  GHadeVisitorManager();
finalization
  if Assigned(FHadeVisitorManager) then
    FreeAndNil(FHadeVisitorManager);

end.

